/**
 * 实现createStore的功能 
 * @export
 * @param {function} reducer
 * @param {any} initState 默认状态
 * @param {any} enhanced 表示 applyMiddleware(log1, log2) 的返回函数
 */
export default function createStore(reducer, initState, enhanced) {

    if (typeof initState === "function") {
        //第二个参数是应用中间件的函数返回值
        enhanced = initState;
        initState = undefined;
    }
    if (typeof enhanced === "function") {
        //进入applyMiddleWare的处理逻辑
        return enhanced(createStore)(reducer, initState);
    }

    let state = initState, // 当前仓库中状态
        currReducer = reducer // 当前reducer
    const listeners = [] // 记录所有的监听器

    // 创建仓库时需要调用一次dispatch
    state = dispatch({ type: '@@redux/INIT.' + getRandomString(7) })

    function dispatch(action) {
        // 验证action 是一个平面对象，且有type属性
        if (!isPlian(action)) {
            throw new TypeError('action must be a plain object')
        }
        if (action.type === undefined) {
            throw new TypeError('action must has a property of type')
        }
        state = currReducer(state, action)
        listeners.forEach(f => f())
    }

    function getState() {
        return state
    }

    function replaceReducer(reducer) {
        currReducer = reducer
    }

    /**
     * 添加一个监听器
     * @param {*} listener
     * @return {*} 
     */
    function subscribe(listener) {
        if (typeof listener !== 'function') {
            throw TypeError('listener must be a function')
        }
        const unListen = () => {
            const index = listeners.findIndex(fun => fun === listener)
            listeners.splice(index, 1)
        }
        listeners.push(listener)
        return unListen
    }

    return { dispatch, getState, subscribe, replaceReducer }
}

/**
 * 判断一个对象是不是平面对象
 * @param {*} obj
 */
function isPlian(obj) {
    if (typeof obj !== 'object' || obj === null) return false;
    // obj.__proto__  ===> Object.getPrototypeOf(obj) 
    return Object.getPrototypeOf(obj) === Object.prototype;
}


/**
 * 得到一个随机长度的字符串
 * @param {number} len
 */
function getRandomString(len) {
    return Math.random().toString(36).substring(2, len).split("").join(".")
}